package de.justphil.tcg.tcgserver.commons.i18n;

import java.util.List;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.regex.Pattern;

import org.slf4j.Logger;

import static de.justphil.tcg.tcgserver.commons.logging.TCGLogging.*;
import de.justphil.tcg.tcgserver.commons.util.LanguageFileLoader;
import de.justphil.tcg.tcgserver.commons.util.StringUtil;
import de.justphil.tcg.tcgserver.commons.config.I18nConfig;
import de.justphil.tcg.tcgserver.commons.exceptions.TCGException;
import de.justphil.tcg.tcgserver.commons.i18n.Error;

import net.jcip.annotations.ThreadSafe;

@ThreadSafe
public class I18n {
	private static final Logger log = logger(I18n.class);
	private static final Logger status = statusLogger(I18n.class);
	
	public static String translate(String key, String locale) {
		return translate(key, createLocale(locale));
	}
	
	public static String translate(String key, String language, String country) {
		String l,c;
		
		if (language == null || country == null) {
			l = I18nConfig.DEFAULT_LANGUAGE;
			c = I18nConfig.DEFAULT_COUNTRY;
		}
		else {
			l = language;
			c = country;
		}
		
		return translate(key, new Locale(l, c));
	}
	
	public static String translate(String key, Locale locale) {
		try {
			String out = null;
			ResourceBundle rb = bundles.get(locale);
			
			if (rb == null) {
				// Locale not available -> try default locale
				log.warn("Locale not available for '{}' -> trying default locale ({})", key, I18nConfig.DEFAULT_LOCALE);
				out = bundles.get(new Locale(I18nConfig.DEFAULT_LANGUAGE, I18nConfig.DEFAULT_COUNTRY)).getString(key);
			}
			else {
				out = rb.getString(key);
			}
			
			return out;
		}
		catch (MissingResourceException mre) {
			// Key not available -> just return the key
			log.warn("Key not available -> just returning the key '{}'", key);
			return key;
		}
	}
	
	public static String translate(String key, Locale locale, Object... replacements) {
		if (replacements == null || replacements.length == 0)
			throw new IllegalArgumentException( "elements == null || elements.length == 0" );
		
		return StringUtil.replaceWildcards(translate(key, locale), replacements);
	}
	
	public static void printSupportedLanguages() {
		status.info("### ################### ###");
		status.info("### AVAILABLE LANGUAGES ###");
		status.info("### ################### ###");
		
		String locale;
		for ( ConcurrentMap.Entry<Locale, ResourceBundle> e : bundles.entrySet() ) {
			locale = e.getKey().getLanguage() + "-" + e.getKey().getCountry();
			if (locale.equals(I18nConfig.DEFAULT_LOCALE))
				status.info("### {}-{} ### (default language)", e.getKey().getLanguage(), e.getKey().getCountry());
			else
				status.info("### {}-{} ###", e.getKey().getLanguage(), e.getKey().getCountry());
		}
	}
	
	public static Locale createLocale(String locale) {
		if (!StringUtil.isNullOrEmpty(locale)) {
			String[] segs = locale.split( Pattern.quote( "-" ) );
			
			if (segs.length == 2) {
				Locale l = new Locale(segs[0], segs[1]);
				
				if (isSupportedLanguage(l)) {
					return l;
				}
			}
		}
		
		return new Locale(I18nConfig.DEFAULT_LANGUAGE, I18nConfig.DEFAULT_COUNTRY);
	}
	
	public static boolean isSupportedLanguage(Locale locale) {
		return bundles.containsKey(locale);
	}
	
	public static Locale determineBestFittingLocale(List<Locale> locales) {
		Locale out = null;
		
		if (locales == null || locales.size() == 0) {
			out = new Locale(I18nConfig.DEFAULT_LANGUAGE, I18nConfig.DEFAULT_COUNTRY);
		}
		
		
		for (Locale locale : locales) {
			if (isSupportedLanguage(locale)) {
				out = locale;
				break;
			}
		}
		
		if (out == null) {
			out = new Locale(I18nConfig.DEFAULT_LANGUAGE, I18nConfig.DEFAULT_COUNTRY);
		}
		
		return out;
	}
	
	private static final ConcurrentMap<Locale, ResourceBundle> bundles = new ConcurrentHashMap<Locale, ResourceBundle>();
	
	/*
	 * Static class initialization is guaranteed to be thread-safe by Java.
	 * Source: http://java.sun.com/docs/books/jls/third_edition/html/execution.html#12.4.2
	 */
	static {
		try {
			List<String> languages = LanguageFileLoader.getLanguageFiles(
					I18nConfig.WEBSOCKETS_LANG_PACKAGE_PATH,
					I18nConfig.WEBSOCKETS_LANG_BUNDLE_NAME
			);
			
			if (languages == null || languages.size() == 0)
				throw new TCGException(Error.SERVER_ERROR_INTERNAL);
			
			Locale locale;
			String[] segs;
			String bundleBase = I18nConfig.WEBSOCKETS_LANG_PACKAGE + "." + I18nConfig.WEBSOCKETS_LANG_BUNDLE_NAME;
			for ( String language : languages ) {
				segs = language.split( Pattern.quote( "-" ) );
				locale = new Locale(segs[0], segs[1]);
				
				bundles.put(locale, ResourceBundle.getBundle(bundleBase, locale));
			}
		}
		catch (Exception e) {
			e.printStackTrace();
			System.exit(1);
		}
	}
}
